package top.stmo.spring.ioc.test1;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import top.stmo.spring.ioc.test1.dao.BookDao;
import top.stmo.spring.ioc.test1.service.BookService;
import top.stmo.spring.ioc.test1.service.impl.BookServiceImpl;

/**
 *   -------------------------IOC、IOC容器、Bean、DI--------------------------
 *
 *   IOC:控制反转
 *
 *   什么是控制反转呢？
 *      使用对象时，由主动new产生对象转换为由外部提供对象，此过程中对象创建控制权由程序转移到外部，
 *      此思想称为控制反转
 *
 *   Spring和IOC之间的关系是什么呢
 *      Spring技术对IOC思想进行了实现
 *      Spring提供了一个容器，称为IOC容器，用来充当IOC思想中的"外部"
 *      IOC思想中的别人[外部]指的就是Spring的IOC容器
 *
 *    IOC容器的作用以及内部存放的是什么?
 *      IOC容器负责对象的创建、初始化等一系列工作，其中包含了数据层和业务层的类对象
 *      被创建或被管理的对象在IOC容器中统称为Bean
 *      IOC容器中放的就是一个个的Bean对象
 *
 *    DI:依赖注入
 *      在容器中建立bean与bean之间的依赖关系的整个过程，称为依赖注入
 *      业务层要用数据层的类对象，以前是自己new的
 *      现在自己不new了，靠别人[外部其实指的就是IOC容器]来给注入进来
 *      这种思想就是依赖注入
 *
 *    Spring的IOC和DI的最终目标就是:充分解耦，具体实现靠:
 *          使用IOC容器管理bean（IOC)
 *          在IOC容器内将有依赖关系的bean进行关系绑定（DI）
 *          最终结果为:使用对象时不仅可以直接从IOC容器中获取，并且获取到的bean已经绑定了所有的依赖关系
 *
 *    Spring所管理的Bean默认是单例的，通过属性配置即可实现多例
 *
 *    依赖注入即为Spring所管理的Bean中的属性进行赋值
 *
 *    小结：
 *      什么是IOC/DI思想?
 *          IOC:控制反转，控制反转的是对象的创建权
 *          DI:依赖注入，绑定对象与对象之间的依赖关系
 *      什么是IOC容器?
 *          Spring创建了一个容器用来存放所创建的对象，这个容器就叫IOC容器
 *      什么是Bean?
 *          容器中所存放的一个个对象就叫Bean或Bean对象
 *
 *
 *    -------------------------Bean的实例化--------------------------
 *
 *    bean是如何创建的呢?
 *      构造方法    (bean标签的id和class属性)
 *
 *    Spring的IOC实例化对象的三种方式分别是:
 *      构造方法(常用)
 *      静态工厂(了解)
 *      实例工厂(了解)
 *          FactoryBean(实用)
 *    这些方式中，重点掌握构造方法和FactoryBean即可
 *    需要注意的一点是，构造方法在类中默认会提供，但是如果重写了构造方法，默认的就会消失，在使用的过程中需要
 *    注意，如果需要重写构造方法，最好把默认的构造方法也重写下
 *
 *    -------------------------Bean的生命周期--------------------------
 *
 *    关于Spring中对bean生命周期控制提供了两种方式:
 *          在配置文件中的bean标签中添加init-method和destroy-method属性
 *          类实现InitializingBean与DisposableBean接口，这种方式了解下即可。
 *    对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:
 *
 *    初始化容器
 *          1.创建对象(内存分配)
 *          2.执行构造方法
 *          3.执行属性注入(set操作)
 *          4.执行bean初始化方法
 *      使用bean
 *          执行业务操作
 *      关闭/销毁容器
 *          执行bean销毁方法
 *
 *    关闭容器的两种方式:
 *      ConfigurableApplicationContext是ApplicationContext的子类
 *          close()方法
 *          registerShutdownHook()方法
 *
 */
public class AppTest1 {

    /**
     *      原始方式
     */
    @Test
    public void test1() {
        BookService bookService = new BookServiceImpl();
        bookService.save();
    }

    /**
     *      Spring ioc 方式
     */
    @Test
    public void test2() {
        //1.导入Spring的坐标spring-context
        //2.配置bean
        //3.获取Ioc容器
        ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
        //4.获取bean
//        BookDao bookDao = (BookDao) act.getBean("bookDao");
//        bookDao.save();

        BookService bookService = (BookService) act.getBean("bookService");
        bookService.save();
    }

    @Test
    public void test3() {
        ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) act.getBean("bookDaoFactory");
        bookDao.save();
    }

    //bean的生命周期
    @Test
    public void test4() {
        ClassPathXmlApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) act.getBean("bookDaoFactory");
        bookDao.save();
//        act.close();
        act.registerShutdownHook();
    }
}
